#include "dialog.h"

#include "SDL.h"

#include "global.h"
#include "drawing.h"
#include "images.h"
#include "palette.h"
#include "text.h"

// minimum dialog box width
static const int DIALOG_W = 300;

// space between buttons on dialog box
static const int BTN_SPACE = 10;

// minimum space inside buttons on dialog
static const int EXTRA_BTN_SPACE = 6;


static void parse_keystroke(char* input, int max_input, SDL_Event* e)
{
	if(e->type == SDL_KEYDOWN && e->key.keysym.unicode)
	{
		int i = strlen(input);

		if(e->key.keysym.unicode < 32)
			switch(e->key.keysym.sym)
			{
				case SDLK_BACKSPACE:
					if(i == 1)
						input[0] = 0;
					else if(i > 0)
					{
						if(input[i-2] & 0x80)
							input[i-2] = 0;
						else
							input[i-1] = 0;
					}
					return;
				default:
					return;
			}

		if(i >= max_input - 1)
			return;

		if(e->key.keysym.unicode < 0x80)
		{
			input[i] = e->key.keysym.unicode;
			input[i+1] = 0;
		}
		else if(e->key.keysym.unicode < 0x800)
		{
			input[i] = (0xc0 | e->key.keysym.unicode >> 6);
			input[i+1] = ((0x80 | e->key.keysym.unicode) & 0x3f);
			input[i+2] = 0;
		}
		else if(e->key.keysym.unicode < 0x800)
		{
			input[i] =   ((0xe0 | e->key.keysym.unicode) >> 12);
			input[i+1] = ((0x80 | e->key.keysym.unicode) >> 6 & 0x3f);
			input[i+2] = ((0x80 | e->key.keysym.unicode) & 0x3f);
			input[i+3] = 0;
		}
		return;
	}
}


static int dialog(char** buttons, int n_buttons, int _default, ButtonImage image, 
		char* input, int max_input, char* fmt, ...)
{
	int i;
	TTF_Font* input_font = pixChicago8;
	SDL_EnableUNICODE(1);
	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);

	Pencil p = { screen, editundo14, (SDL_Color) { 0,0,0 }, (SDL_Color) { 255,255,255} };
	
	// create print string
	char message[1024];
	va_list args;
	va_start(args, fmt);
	vsnprintf(message, 1024, fmt, args);
	va_end(args);

	// get text surfaces
	SDL_Surface* txt_sf = dbl_text(p, 40, message);
	SDL_Surface** opt_sf = malloc(sizeof(SDL_Surface*) * n_buttons);
	SDL_Rect* btn_r = malloc(sizeof(SDL_Rect) * n_buttons);
	int max_w = 50;
	for(i=0; i<n_buttons; i++)
	{
		opt_sf[i] = dbl_text(p, 0, buttons[i]);
		if(opt_sf[i]->w >max_w)
			max_w = opt_sf[i]->w;
	}

	// calculate dialog size
	int box_w = DIALOG_W;
	int input_h = (input == NULL) ? 0 : TTF_FontLineSkip(input_font);
	if(box_w < (n_buttons * (max_w+2*EXTRA_BTN_SPACE) + ((n_buttons-1) * BTN_SPACE)) + 20)
		box_w = (n_buttons * (max_w+2*EXTRA_BTN_SPACE) + ((n_buttons-1) * BTN_SPACE)) + 20;
	SDL_Rect area = { 
		(screen->w/2 - box_w/2),
		(screen->h/2 - (txt_sf->h + 80) / 2) + (input_h / 2),
		box_w, txt_sf->h + 80 + input_h
	};

	// store current screen to restore next
	SDL_Surface* stored_sf = SDL_CreateRGBSurface(screen->flags, area.w, 
			area.h, 8, 0, 0, 0, 0);
	SDL_SetPalette(stored_sf, SDL_LOGPAL|SDL_PHYSPAL, 
			screen->format->palette->colors, 0, 256);
	SDL_BlitSurface(screen, &area, stored_sf, NULL);

	// draw box
	fill_3d_box(screen, &area, UPPER);

	// draw text
	SDL_BlitSurface(txt_sf, NULL, screen,
			&(SDL_Rect) { (screen->w/2 - txt_sf->w/2),
			              (screen->h/2 - (txt_sf->h + 100) / 2) + 30 + input_h/2 });
	
	// TODO - draw image
	
	// draw buttons
	int base = screen->w/2;
	base += (BTN_SPACE + EXTRA_BTN_SPACE) / 2;
	base -= (max_w + BTN_SPACE + 2*EXTRA_BTN_SPACE) * (n_buttons / 2);
	if(n_buttons % 2 == 1) // odd
		base -= (max_w + BTN_SPACE + 2*EXTRA_BTN_SPACE) / 2;
	for(i=0; i<n_buttons; i++)
	{
		btn_r[i] = (SDL_Rect) {
			base,
			screen->h/2 + area.h/2 - 15 - (TTF_FontLineSkip(p.font) + 2*EXTRA_BTN_SPACE) + input_h,
			max_w + 2*EXTRA_BTN_SPACE,
			TTF_FontLineSkip(p.font) + 2*EXTRA_BTN_SPACE 
		};
		fill_3d_box(screen, &btn_r[i], UPPER);
		SDL_BlitSurface(opt_sf[i], NULL, screen, &(SDL_Rect) {
				base + (max_w + 2*EXTRA_BTN_SPACE) / 2 - opt_sf[i]->w / 2,
				screen->h/2 + area.h/2 - 15 - TTF_FontLineSkip(p.font) - EXTRA_BTN_SPACE  + input_h});
		base += max_w + 2*EXTRA_BTN_SPACE + BTN_SPACE;

		// draw default light
		if(i == _default)
			SDL_BlitSurface(images[DEFAULT_OPTION], NULL, screen,
					&(SDL_Rect) { btn_r[i].x + 4, 
					              btn_r[i].y + 4 });
	}

	// draw input
	SDL_Rect input_area = {
		area.x + 40,
		screen->h/2 + area.h/2 - 15 - (TTF_FontLineSkip(p.font) + 2*EXTRA_BTN_SPACE) - 12,
		area.w - 80,
		TTF_FontLineSkip(input_font) + 2
	};
	SDL_Rect cursor = {
		input_area.x + 3,
		input_area.y + 1,
		3,
		TTF_FontLineSkip(input_font)
	};

	// pencil to write input
	Pencil p_input = { screen, pixChicago8, (SDL_Color) { 0, 255, 0 }, 
		(SDL_Color) { 0,80,0 } };

	// main loop
	SDL_Event e;
	int option = -1;
	int frame = 0;
	while(option == -1)
	{
		Uint32 next = SDL_GetTicks() + (1000/60);

		// draw input
		if(input)
		{
			SDL_FillRect(screen, &input_area, BLACK);
			cursor.x = input_area.x + 3;
			if(strcmp(input, "") != 0)
			{
				SDL_Surface* input_text = dbl_text(p_input, 0, input);
				SDL_BlitSurface(input_text, NULL, screen, &(SDL_Rect) {
						input_area.x + 3, input_area.y + 1 });
				cursor.x += input_text->w;
				SDL_FreeSurface(input_text);
			}
			SDL_FillRect(screen, &cursor, CURSOR);
		}

		// update screen
		SDL_UpdateRect(screen, area.x, area.y, area.w, area.h);

		// get inputs
		while(SDL_PollEvent(&e))
			if(e.type == SDL_MOUSEBUTTONDOWN)
			{
				for(i=0; i<n_buttons; i++)
					if(e.button.x >= btn_r[i].x
					&& e.button.x < btn_r[i].x + btn_r[i].w
					&& e.button.y >= btn_r[i].y
					&& e.button.y < btn_r[i].y + btn_r[i].h)
						option = i;
			}
			else if(e.type == SDL_KEYDOWN)
			{
				if(e.key.keysym.sym == SDLK_RETURN
				|| e.key.keysym.sym == SDLK_KP_ENTER)
				{
					if(_default >= 0 && _default < n_buttons)
						option = _default;
				}
				else
					parse_keystroke(input, max_input, &e);
						

			}
			else if(e.type == SDL_QUIT)
			{
				if(_default != -1)
					option = _default;
				else
					option = 0;
			}

		// wait for next frame
		while(SDL_GetTicks() < next)
			SDL_Delay(1);

		// blink cursor
		if(frame++ % 30 == 0)
		{
			if(screen->format->palette->colors[CURSOR].g == 255)
				screen->format->palette->colors[CURSOR].g = 0;
			else
				screen->format->palette->colors[CURSOR].g = 255;
			SDL_SetPalette(screen, SDL_LOGPAL|SDL_PHYSPAL, &screen->format->palette->colors[CURSOR], CURSOR, 1);
		}
	}

	// restore saved image
	SDL_BlitSurface(stored_sf, NULL, screen, &area);

	// cleanup
	SDL_FreeSurface(txt_sf);
	free(btn_r);
	for(i=0; i<n_buttons; i++)
		SDL_FreeSurface(opt_sf[i]);
	free(opt_sf);
	SDL_FreeSurface(stored_sf);

	SDL_EnableUNICODE(0);
	SDL_EnableKeyRepeat(0, 0);

	return option;
}


void message(ButtonImage image, char* fmt, ...)
{
	// create print string
	char message[1024];
	va_list args;
	va_start(args, fmt);
	vsnprintf(message, 1024, fmt, args);
	va_end(args);

	// call dialog
	(void) dialog((char*[]) { _("Ok") }, 1, 0, image, NULL, 0, message);
}


_Bool question(ButtonImage image, _Bool _default, char* fmt, ...)
{
	// create print string
	char message[1024];
	va_list args;
	va_start(args, fmt);
	vsnprintf(message, 1024, fmt, args);
	va_end(args);

	// call dialog
	return dialog((char*[]) { _("Yes"), _("No") }, 2, _default ? 0 : 1, 
			image, NULL, 0, message) == 0 ? true : false;
}


/* Create a text input dialog. The parameters are:
 *   - image: the image used on the dialog (WARNING, INFORMATION, etc...)
 *   - input: the char* variable that'll hold the answer. It must be big enough.
 *            The current variable text will appear on the dialog.
 *   - input_size: the max size for the input
 *   - cancel_button: if there is a cancel button
 *   - fmt: the text to be displayed.
 *
 * The function returns true if the user pressed "ok", and "cancel" otherwise. */
_Bool input(ButtonImage image, char* input, int input_size, _Bool cancel_button, 
		char* fmt, ...)
{
	char message[1024];
	va_list args;
	va_start(args, fmt);
	vsnprintf(message, 1024, fmt, args);
	va_end(args);

	char** buttons;
	int n_buttons;

	if(cancel_button)
	{
		buttons = (char*[]) { _("Ok"), _("Cancel") };
		n_buttons = 2;
	}
	else
	{
		buttons = (char*[]) { _("Ok") };
		n_buttons = 1;
	}

	return dialog(buttons, n_buttons, 0, image, input, input_size, message) == 0 ? true : false;
}
